package server;
// UpdateThread.java
// One instance of this thread runs for the game
// It moves players around and drops items
// It is the clock for the game.

// Holds: 	updateGame()
//			updateClients()
//			addRequest(ClientRequest request, int ID)

import java.util.Random;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.Timer;

import client.ClientRequest;
import client.ServerResponse;

import java.util.ArrayList;
import java.awt.Point;
import java.net.Socket;
import java.net.SocketException;

class UpdateThread implements Runnable, ActionListener
{
	private static final int GameUpdatePeriod = 50;		// Update game every 50 ms
	private static final int ClientUpdateCycles = 10;	// Update clients every 10 cycles
	private int updateClock = 0;
	private Timer t = new Timer(GameUpdatePeriod, this);
	private ArrayList<ClientData> clients = new ArrayList<ClientData>();  // Data structure for clients
	private ArrayList<Point> items = new ArrayList<Point>();	// Locations of points
	private Random r = new Random();


	// Update all units un the game
	// Calls updateClients() every ClientUpdateCycles times
	private void updateGame()
	{
		// Move everyone from current position towards desired position
		for(int i = 0; i < clients.size(); i++)
		{
			ClientData c = clients.get(i);
			if(c.getX() < c.getXDesired())
			{
				c.setX(c.getX() + 1);
			}
			if(c.getX() > c.getXDesired())
			{
				c.setX(c.getX() - 1);
			}
			if(c.getY() < c.getYDesired())
			{
				c.setY(c.getY() + 1);
			}
			if(c.getY() > c.getYDesired())
			{
				c.setY(c.getY() - 1);
			}
			// Pick up item
			for(int j = 0; j < items.size(); j++)
			{
				Point p = items.get(j);
				if(c.getX() > p.getX()-5 && c.getX() < p.getX()+5 && c.getY() > p.getY()-5 && c.getY() < p.getY()+5)
				{
					items.remove(j);
					c.setScore(c.getScore()+1);
				}
			}
		}
		// Maybe drop an item
		if(r.nextInt(1000)<10 && items.size() < 20)
		{
			items.add(new Point(r.nextInt(600)+1, r.nextInt(600)+1));
		}
		// Update clients
		updateClock++;
		if(updateClock >= ClientUpdateCycles)
		{
			updateClients();
			updateClock = 0;
		}
	}


	// Send current game state to all clients
	private void updateClients()
	{
		// Package up game state
		Point[] p = new Point[clients.size()];
		for(int i = 0; i < p.length; i++)
		{
			p[i] = new Point(clients.get(i).getX(), clients.get(i).getY());
		}
		Point[] item = new Point[items.size()];
		item = items.toArray(item);
		// Loop through players
		for(int i = 0; i < clients.size(); i++)
		{
			ClientData c = clients.get(i);
			try
			{
				if(c.isLoggedIn()) // Send Server Response
				{
					c.getNetworkOutput().send(new ServerResponse(c.getID(), c.getScore(), c.getX(), c.getY(), p, item));
				}
				else // Ping the connection to make sure it's alive
				{
					c.getNetworkOutput().send(new ServerResponse(-2));
				}
			}
			catch(SocketException e)
			{
				// Log client out
				System.out.println("Client ID "+c.getID()+" logged off.");
				clients.remove(c);
				System.out.println("There are " + clients.size() + " clients connected.");
			}
		}
	}


	// Take a request from a client
	public void addRequest(ClientRequest request, int ID)
	{
		// Get client object based on request ID
		ClientData c = clients.get(0);
		for(int i = 0; i < clients.size(); i++)
		{
			if(clients.get(i).getID() == ID)
			{
				c = clients.get(i);
			}
		}
		// Set things
		if(c.isLoggedIn())
		{
			c.setXDesired(request.getX());
			c.setYDesired(request.getY());
		}
		else
		{
			// Client is trying to log in
			// Add database code here to check login combo
			// Something like
			// if(Database.verifyPassword(request.getUsername(), request.getPassword()))
			// {
				// c.setLoggedIn(true);
			// }
			c.setLoggedIn(true);


			if(!c.isLoggedIn())// Still not logged in
			try
			{
				c.getNetworkOutput().send(new ServerResponse(-1));
			}
			catch(SocketException e)
			{
				// Log client out
				System.out.println("Client ID "+c.getID()+" logged off.");
				clients.remove(c);
				System.out.println("There are " + clients.size() + " clients connected.");
			}
		}
	}



	// Entry point
	public void run()
	{
		t.start();  // Start game clock
	}


	// Update all units in the game
	public void actionPerformed(ActionEvent e)
	{
		updateGame();
	}


	// Add a new client
	public void addClient(Socket s)
	{
		// Find an ID
		boolean used = false;
		for(int i = 0; i < 200; i++)
		{

			used = false;
			for(int j = 0; j < clients.size(); j++)
			{
				if(clients.get(j).getID() == i)
				{
					used = true;
				}
			}
			if(!used)
			{
				// Use ID to create new client
				clients.add(new ClientData(i, s, this));
				System.out.println("Client logged on as ID "+i+" From IP:"+s.getInetAddress()+" On Port:"+s.getPort());
				System.out.println("There are " + clients.size() + " clients connected.");
				break;
			}
		}
	}
}
